//
//  HJGoogleCloudStorage.m
//  GoogleLoginICloud
//
//  Created by lx on 2024/1/6.
//

#import "GoogleCloudStorage.h"
#import <CoreServices/UTType.h>
#import <GoogleSignIn/GoogleSignIn.h>

@implementation GoogleCloudStorage

static GTLRDriveService *service;

+ (GTLRDriveService *)driveService {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        service = [[GTLRDriveService alloc] init];
        service.shouldFetchNextPages = YES;
        service.retryEnabled = YES;
    });
    service.authorizer = [GIDSignIn sharedInstance].currentUser.fetcherAuthorizer;
    return service;
}

+ (void)uploadFileAtPath:(NSString *)path progress:(nullable void (^)( unsigned long long numberOfBytesRead, unsigned long long dataLength))uploadProgress completion:(void (^__nullable)(GTLRDrive_File  * _Nullable file, NSError * _Nullable error))completion {
    
    

    if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
        if (completion) {
            completion(nil,[NSError errorWithDomain:[NSString stringWithFormat:@"%@.%@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"], @"GoogleCloudStorage"] code:-10001 userInfo:@{
                NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:@"No Upload File Found Path: %@", path]
            }]);
        }
        return;
    }
    
    NSURL *fileToUploadURL = [NSURL fileURLWithPath:path];
    
    NSString *filename = [path lastPathComponent];
    NSString *mimeType = [self MIMETypeFileName:filename defaultMIMEType:@"binary/octet-stream"];
    GTLRUploadParameters *uploadParameters = [GTLRUploadParameters uploadParametersWithFileURL:fileToUploadURL MIMEType:mimeType];
    
 
    GTLRDrive_File *newFile = [GTLRDrive_File object];
    newFile.name = filename;
   
    
    
    GTLRDriveQuery_FilesCreate *query = [GTLRDriveQuery_FilesCreate queryWithObject:newFile uploadParameters:uploadParameters];
    query.executionParameters.uploadProgressBlock = ^(GTLRServiceTicket *callbackTicket,
                                                      unsigned long long numberOfBytesRead,
                                                      unsigned long long dataLength) {
        if (uploadProgress) {
            uploadProgress(numberOfBytesRead, dataLength);
        }
    };
    
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDrive_File *uploadedFile,NSError *callbackError) {
        
        !completion ?: completion(uploadedFile, callbackError);
    }];
    
}

+ (void)downloadFile:(NSString *)fileId toDestinationURL:(NSURL *)destinationURL completion:(void (^__nullable)(NSError * _Nullable error))completion {
    
    GTLRQuery *query = [GTLRDriveQuery_FilesGet queryForMediaWithFileId:fileId];
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDataObject *object, NSError *callbackError) {
        
        if (callbackError) {
            !completion ?: completion( callbackError);
            return;
        }
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSError *writeError = nil;
            [object.data writeToURL:destinationURL options:NSDataWritingAtomic error:&writeError];
            dispatch_async(dispatch_get_main_queue(), ^{
                !completion ?: completion(writeError);
            });
        });
    }];
}

+ (void)fetchFile:(NSString *)fileId completion:(void (^__nullable)(GTLRDrive_File * _Nullable file, NSError * _Nullable error))completion {
    GTLRDriveQuery_FilesGet *query = [GTLRDriveQuery_FilesGet queryWithFileId:fileId];
    query.completionBlock = ^(GTLRServiceTicket *callbackTicket, GTLRDrive_File *obj,
                              NSError *callbackError) {
        
        
        !completion ?: completion(obj, callbackError);
    };
    
    GTLRBatchQuery *batchQuery = [GTLRBatchQuery batchQuery];
    [batchQuery addQuery:query];
    [service executeQuery:batchQuery
        completionHandler:^(GTLRServiceTicket *callbackTicket,
                            GTLRBatchResult *batchResult,
                            NSError *callbackError) {}];
}

+ (void)readFile:(NSString *)fileId completion:(void (^__nullable)(NSData * _Nullable fileData, NSError * _Nullable error))completion {
    GTLRQuery *query = [GTLRDriveQuery_FilesGet queryForMediaWithFileId:fileId];
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDataObject *object, NSError *callbackError) {
        dispatch_async(dispatch_get_main_queue(), ^{
            !completion ?: completion(object.data, callbackError);
        });
    }];
}

+ (void)fetchFileWithName:(NSString *)name completion:(void (^__nullable)(NSArray <GTLRDrive_File *> * _Nullable files, NSError * _Nullable error))completion {
    GTLRDriveQuery_FilesList *query = [GTLRDriveQuery_FilesList query];
    query.pageSize = 1000;
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDrive_FileList *fileList, NSError *callbackError) {
        NSMutableArray *datas = [NSMutableArray array];
        for (GTLRDrive_File *file in fileList.files) {
            if ([file.name containsString:name]) {
                [datas addObject:file];
            }
        }
        !completion ?: completion(datas, callbackError);
    }];
}

+ (void)fetchFileListCompletion:(void (^__nullable)(GTLRDrive_FileList * _Nullable files, NSError * _Nullable error))completion {
    GTLRDriveQuery_FilesList *query = [GTLRDriveQuery_FilesList query];
    query.fields = @"kind,nextPageToken,files(mimeType,id,kind,name,webViewLink)";
//    query.pageSize = 50;
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDrive_FileList *fileList, NSError *callbackError) {
        !completion ?: completion(fileList, callbackError);
    }];
}

+ (void)deleteFile:(NSString *)fileId completion:(void (^__nullable)(NSError * _Nullable error))completion {
    GTLRDriveQuery_FilesDelete *query = [GTLRDriveQuery_FilesDelete queryWithFileId:fileId];
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, id nilObject, NSError *callbackError) {
        !completion ?: completion(callbackError);
    }];
}

+ (void)createAFolderWithName:(NSString *)name completion:(void (^__nullable)(GTLRDrive_File * _Nullable file, NSError * _Nullable error))completion {
    GTLRDrive_File *folderObj = [GTLRDrive_File object];
    folderObj.name = name;
    folderObj.mimeType = @"application/vnd.google-apps.folder";
    GTLRDriveQuery_FilesCreate *query = [GTLRDriveQuery_FilesCreate queryWithObject:folderObj uploadParameters:nil];
    [[self driveService] executeQuery:query completionHandler:^(GTLRServiceTicket *callbackTicket, GTLRDrive_File *folderItem, NSError *callbackError) {
        !completion ?: completion(folderItem, callbackError);
    }];
}


+ (NSString *)MIMETypeFileName:(NSString *)path
               defaultMIMEType:(NSString *)defaultType {
    NSString *result = defaultType;
    NSString *extension = [path pathExtension];
    CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
                                                            (__bridge CFStringRef)extension, NULL);
    if (uti) {
        CFStringRef cfMIMEType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
        if (cfMIMEType) {
            result = CFBridgingRelease(cfMIMEType);
        }
        CFRelease(uti);
    }
    return result;
}



@end
